if {"::tcltest" ni [namespace children]} {
	package require tcltest
	namespace import ::tcltest::*
}

package require rl_json
namespace path {::rl_json}

test template_string-1.1 {Produce a JSON doc with interpolated values, no dict} -setup { #<<<
	set bar	"Bar"
	unset -nocomplain a
	array set a {
		x		str
		y		123
		on		yes
		off		0
		subdoc	{{"inner": "~S:bar"}}
		subdoc2	{{"inner2": "~S:bar"}}
		subdoc3	null
	}
} -body {
	json template_string {
		{
			"foo": "~S:bar",
			"baz":  [
				"~S:a(x)",
				"~N:a(y)",
				123.4,
				"~B:a(on)",
				"~B:a(off)",
				"~S:a(not_defined)",
				"~L:~S:not a subst",
				"~J:a(subdoc)",
				"~T:a(subdoc2)",
				"~J:a(subdoc3)"
			]
		}
	}
} -cleanup {
	unset -nocomplain bar a
} -result {{"foo":"Bar","baz":["str",123,123.4,true,false,null,"~S:not a subst",{"inner":"~S:bar"},{"inner2":"Bar"},null]}}
#>>>
test template_string-1.2 {Produce a JSON doc with interpolated values, using dict} -body { #<<<
	json template_string {
		{
			"foo": "~S:bar",
			"baz":  [
				"~S:x",
				"~N:y",
				123.4,
				"~B:on",
				"~B:off",
				"~S:not_defined",
				"~L:~S:not a subst",
				"~J:subdoc",
				"~T:subdoc2",
				"~J:subdoc3",
				"~S:baz"
			]
		}
	} {
		foo		"Foo"
		bar		"Ba\"r"
		baz		"Baz"
		x		str
		y		123
		on		yes
		off		0
		subdoc	{{"inner" : "~S:foo"}}
		subdoc2	{{"inner2" : "~S:foo"}}
		subdoc3	null
	}
} -result {{"foo":"Ba\"r","baz":["str",123,123.4,true,false,null,"~S:not a subst",{"inner":"~S:foo"},{"inner2":"Foo"},null,"Baz"]}}
#>>>
test template_string-1.3 {Produce a JSON doc with interpolated values, subst object keys, using dict} -body { #<<<
	json template_string {
		{
			"~S:foo": "~S:bar",
			"baz":  [
				"~S:x",
				"~N:y",
				123.4,
				"~B:on",
				"~B:off",
				"~S:not_defined",
				"~L:~S:not a subst",
				"~J:subdoc",
				"~T:subdoc2",
				"~J:subdoc3",
				"~S:baz"
			]
		}
	} {
		foo		"Foo"
		bar		"Ba\"r"
		baz		"Baz"
		x		str
		y		123
		on		yes
		off		0
		subdoc	{{"inner" : "~S:foo"}}
		subdoc2	{{"inner2" : "~S:foo"}}
		subdoc3	null
	}
} -result {{"Foo":"Ba\"r","baz":["str",123,123.4,true,false,null,"~S:not a subst",{"inner":"~S:foo"},{"inner2":"Foo"},null,"Baz"]}}
#>>>
test template_string-1.4 {Invalid interpolated type key fallthrough} -body { #<<<
	json template_string {
		{
			"foo": "~S:foo",
			"bar": "~A:bar"
		}
	} {
	}
} -result {{"foo":null,"bar":"~A:bar"}}
#>>>
test template_string-2.1 {Test interpolated numeric validation} -body { #<<<
	json template_string {
		{
			"Foo": "~N:num",
			"Bar": "baz"
		}
	} {
		num	""
	}
} -returnCodes error -result {Error substituting value from "num" into template, not a number: ""}
#>>>
test template_string-3.1 {Non-string key subst: number} -body { #<<<
	list [catch {
		json template_string { {"~N:v":"bar"} } {v 1}
} r o] [expr {[dict exists $o -errorcode] ? [dict get $o -errorcode] : ""}] $r
} -cleanup {
	unset -nocomplain r o
} -result [list 1 NONE {Only strings allowed as object keys, got ~N:v}]
#>>>
test template_string-3.2 {Non-string key subst: true} -body { #<<<
	list [catch {
		json template_string { {"~B:v":"bar"} } {v 1}
} r o] [expr {[dict exists $o -errorcode] ? [dict get $o -errorcode] : ""}] $r
} -cleanup {
	unset -nocomplain r o
} -result [list 1 NONE {Only strings allowed as object keys, got ~B:v}]
#>>>
test template_string-3.3 {Non-string key subst: false} -body { #<<<
	list [catch {
		json template_string { {"~B:v":"bar"} } {v 0}
} r o] [expr {[dict exists $o -errorcode] ? [dict get $o -errorcode] : ""}] $r
} -cleanup {
	unset -nocomplain r o
} -result [list 1 NONE {Only strings allowed as object keys, got ~B:v}]
#>>>
test template_string-3.4 {Non-string key subst: null} -body { #<<<
	list [catch {
		json template_string { {"~S:v":"bar"} } {}
} r o] [expr {[dict exists $o -errorcode] ? [dict get $o -errorcode] : ""}] $r
} -cleanup {
	unset -nocomplain r o
} -result [list 1 NONE {Only strings allowed as object keys}]
#>>>
test template_string-3.5 {Non-string key subst: literal} -body { #<<<
	json template_string { {"~L:~N:v":"bar"} } {}
} -result {{"~N:v":"bar"}}
#>>>

try { # Check string quoting
	set leading		"fooは"
	set trailing	"barほ"
	for {set i 0} {$i <= 0x1F} {incr i} {
		lappend range	[format 0x%02X $i]
	}
	lappend range 0x22 0x5C 0x2F
	set special	{
		0x08	{\b}
		0x09	{\t}
		0x0A	{\n}
		0x0C	{\f}
		0x0D	{\r}
		0x22	{\"}
		0x5C	{\\}
		0x2F	{/}
	}
	foreach c $range {
		set char	[format %c $c]
		if {[dict exists $special $c]} {
			set expect	[dict get $special $c]
		} else {
			set expect	[format {\u%04X} $c]
		}
		test template_string-4.$c.1 "String quoting: $c -> $expect, no leading, no trailing" -setup { #<<<
			set str	$char
		} -body {
			json template_string {"~S:str"}
		} -cleanup {
			unset -nocomplain str
		} -result "\"$expect\""
		#>>>
		test template_string-4.$c.2 "String quoting: $c -> $expect, leading, no trailing" -setup { #<<<
			set str	"$leading$char"
		} -body {
			json template_string {"~S:str"}
		} -cleanup {
			unset -nocomplain str
		} -result "\"$leading$expect\""
		#>>>
		test template_string-4.$c.3 "String quoting: $c -> $expect, no leading, trailing" -setup { #<<<
			set str	"$char$trailing"
		} -body {
			json template_string {"~S:str"}
		} -cleanup {
			unset -nocomplain str
		} -result "\"$expect$trailing\""
		#>>>
		test template_string-4.$c.4 "String quoting: $c -> $expect, leading, trailing" -setup { #<<<
			set str	"$leading$char$trailing"
		} -body {
			json template_string {"~S:str"}
		} -cleanup {
			unset -nocomplain str
		} -result "\"$leading$expect$trailing\""
		#>>>
	}
} finally {
	unset -nocomplain c char expect range i special
}

test template_string-5.1 {Not quite a template} -body { #<<<
	json template_string {
		{
			"foo": "~X:bar",
			"~s:bar": null
		}
	}
} -result {{"foo":"~X:bar","~s:bar":null}}
#>>>
test template_string-6.1 {too few args} -body { #<<<
	json template_string 
} -returnCodes error -result {wrong # args: should be "*template_string json_template ?source_dict?"} -match glob
#>>>
test template_string-6.2 {too many args} -body { #<<<
	json template_string {"~S:foo"} bar baz
} -returnCodes error -result {wrong # args: should be "*template_string json_template ?source_dict?"} -match glob
#>>>

::tcltest::cleanupTests
return

# vim: ft=tcl foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4
